package com.zxy.ziems.server.device.service.impl;

import cn.hutool.core.util.StrUtil;
import com.zxy.btp.common.util.JsonUtils;
import com.zxy.ziems.common.pojo.collector.ChannelDevice;
import com.zxy.ziems.server.device.mapper.ChannelDeviceMapper;
import com.zxy.ziems.server.device.modules.impl.DeviceChannelProcessorManager;
import com.zxy.ziems.server.device.pojo.dto.ChannelDeviceDTO;
import com.zxy.ziems.server.device.pojo.entity.*;
import com.zxy.ziems.server.device.pojo.vo.ChannelDeviceVO;
import com.zxy.ziems.server.device.pojo.vo.DeviceTypeVO;
import com.zxy.ziems.server.device.pojo.vo.DeviceVO;
import com.zxy.ziems.server.device.service.*;
import com.zxy.ziems.server.mybatis.core.query.WrapperX;
import com.zxy.ziems.server.mybatis.core.service.ServiceImplX;
import com.zxy.ziems.server.utils.AssertUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 10348359
 * @create 2024-03-26 0:11
 */
@Service
@Slf4j
public class ChannelDeviceServiceImpl extends ServiceImplX<ChannelDeviceMapper, ChannelDeviceEntity> implements ChannelDeviceService{
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(ChannelDeviceDTO<?> dto) {
        DeviceEntity deviceEntity = deviceService.getById(dto.getDeviceId());
        AssertUtil.nonNull(deviceEntity, "设备不存在");

        ChannelEntity channelEntity = channelService.getById(dto.getChannelId());
        AssertUtil.nonNull(channelEntity, "通讯信道不存在");
        AssertUtil.isTrue(Objects.equals(channelEntity.getDeviceTypeCode(), deviceEntity.getTypeCode()), "通讯信道和设备类型不匹配");

        ProtocolEntity protocolEntity = protocolService.getById(channelEntity.getProtocolId());
        AssertUtil.nonNull(protocolEntity, "协议不存在");

        ChannelDeviceEntity channelDeviceEntity = getOne(WrapperX.<ChannelDeviceEntity>lambdaQuery()
                .eq(ChannelDeviceEntity::getDeviceId, dto.getDeviceId()));
        if (Objects.isNull(channelDeviceEntity)) {

        } else if (Objects.equals(channelDeviceEntity.getChannelId(), dto.getChannelId())) {
            AssertUtil.isTrue(false, "请勿重复在通道内添加设备");
        } else {
            AssertUtil.isTrue(false, "设备已经被添加到别的通道里了，请先解绑" );
        }

        ChannelDeviceEntity entity = dto.buildEntity();

        String protocol = protocolEntity.getCode();
        String channelId = entity.getChannelId();
        String deviceId = entity.getDeviceId();
        processorManager.doProcessAdvancedConfigIfPresentBy(
                protocol,
                dto.getAdvanced(),
                (processor, o)-> {
                    processor.doBeforeEncodeAdvancedConfigActionTrigger(o, protocol, channelId, deviceId);
                    entity.setAdvanced(JsonUtils.toJSONString(o));
                });
        save(entity);

        deviceEntity = new DeviceEntity();
        deviceEntity.setId(dto.getDeviceId());
        deviceEntity.setModel(dto.getModel());
        deviceEntity.setBrand(dto.getBrand());
        deviceService.updateBy(deviceEntity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(ChannelDeviceDTO<?> dto) {
        ChannelDeviceEntity entity = getById(dto.getId());
        AssertUtil.nonNull(entity, "配置不存在");

        DeviceEntity deviceEntity = deviceService.getById(dto.getDeviceId());
        AssertUtil.nonNull(deviceEntity, "设备不存在");

        ChannelEntity channelEntity = channelService.getById(dto.getChannelId());
        AssertUtil.nonNull(channelEntity, "通讯信道不存在");
        AssertUtil.isTrue(Objects.equals(channelEntity.getDeviceTypeCode(), deviceEntity.getTypeCode()), "通讯信道和设备类型不匹配");

        ProtocolEntity protocolEntity = protocolService.getById(channelEntity.getProtocolId());
        AssertUtil.nonNull(protocolEntity, "协议不存在");

        ChannelDeviceEntity channelDeviceEntity = getOne(WrapperX.<ChannelDeviceEntity>lambdaQuery()
                .eq(ChannelDeviceEntity::getDeviceId, dto.getDeviceId()));
        if (Objects.isNull(channelDeviceEntity) || Objects.equals(channelDeviceEntity.getId(), dto.getId())) {

        } else if (Objects.equals(channelDeviceEntity.getChannelId(), dto.getChannelId())) {
            AssertUtil.isTrue(false, "请勿重复在通道内添加设备");
        } else {
            AssertUtil.isTrue(false, "设备已经被添加到别的通道里了，请先解绑" );
        }

        ChannelDeviceEntity updateEntity = dto.buildEntity();

        String protocol = protocolEntity.getCode();
        String channelId = entity.getChannelId();
        String deviceId = entity.getDeviceId();
        processorManager.doProcessAdvancedConfigIfPresentBy(
                protocol,
                dto.getAdvanced(),
                (processor, o)-> {
                     processor.doBeforeEncodeAdvancedConfigActionTrigger(o, protocol, channelId, deviceId);
                    updateEntity.setAdvanced(JsonUtils.toJSONString(o));
                });
        updateById(updateEntity);

        deviceEntity = new DeviceEntity();
        deviceEntity.setId(dto.getDeviceId());
        deviceEntity.setModel(dto.getModel());
        deviceEntity.setBrand(dto.getBrand());
        deviceService.updateBy(deviceEntity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(String id) {
        if (StrUtil.isBlank(id)) {
            return;
        }
        removeById(id);
    }

    @Override
    public ChannelDeviceEntity getByDeviceId(String deviceId) {
        return getOne(ChannelDeviceEntity::getDeviceId, deviceId);
    }

    @Override
    public ChannelDeviceVO<Object> detailById(String id) {

        ChannelDeviceEntity entity = getById(id);
        if (Objects.isNull(entity)) {
            return null;
        }
        String channelId = entity.getChannelId();
        String deviceId = entity.getDeviceId();

        DeviceEntity deviceEntity = deviceService.getById(deviceId);
        DeviceTypeEntity deviceTypeEntity = deviceTypeService.getByCode(deviceEntity.getTypeCode());

        ProtocolEntity protocolEntity = protocolService.getByChannelId(channelId);
        String protocol = Objects.isNull(protocolEntity) ? null : protocolEntity.getCode();


        ChannelDeviceVO<Object> vo = doConvertDeviceEntityToVO(entity, deviceEntity, deviceTypeEntity);

        processorManager.doProcessDecodeAdvancedConfigIfPresentBy(
                protocol,
                entity.getAdvanced(),
                (p, config)-> {
                    Object r = p.doDecodeAdvancedConfig(config, protocol, channelId, deviceId);
                    vo.setAdvanced(r);
                }
       );
        return vo;
    }

    @Override
    public List<ChannelDevice> deviceListByChannelId(String channelId) {
        return baseMapper.selectDeviceListByChannelId(channelId);
    }

    @Override
    public void addEntity(ChannelDeviceEntity channelDeviceEntity) {
        save(channelDeviceEntity);
    }

    private ChannelDeviceVO<Object> doConvertDeviceEntityToVO(ChannelDeviceEntity entity, DeviceEntity deviceEntity, DeviceTypeEntity deviceTypeEntity) {
        if ( entity == null ) {
            return null;
        }

        ChannelDeviceVO<Object> vo = new ChannelDeviceVO<>();
        vo.setId(entity.getId());

        DeviceVO<Object> deviceVO = new DeviceVO<>();
        deviceVO.setId(deviceEntity.getId());
        deviceVO.setName(deviceEntity.getName());
        deviceVO.setCode(deviceEntity.getCode());
        deviceVO.setBrand(deviceEntity.getBrand());
        deviceVO.setModel(deviceEntity.getModel());

        if (Objects.nonNull(deviceTypeEntity)) {
            DeviceTypeVO deviceTypeVO = new DeviceTypeVO();
            deviceTypeVO.setId( deviceTypeEntity.getId() );
            deviceTypeVO.setCode( deviceTypeEntity.getCode() );
            deviceTypeVO.setName( deviceTypeEntity.getName() );
            deviceVO.setType(deviceTypeVO);
        }

        vo.setDevice(deviceVO);
        return vo;
    }

    @Override
    public List<ChannelDeviceVO<Object>> listByChannelId(String channelId) {
        List<ChannelDeviceEntity> list = list(ChannelDeviceEntity::getChannelId, channelId);
        Set<String> deviceIdSet = list.stream().map(ChannelDeviceEntity::getDeviceId).collect(Collectors.toSet());

        Map<String, DeviceEntity> deviceMap = deviceService.listByIdList(deviceIdSet).stream()
                .collect(Collectors.toMap(DeviceEntity::getId, (a) -> a));

        return list.stream()
                .map((entity)-> doConvertDeviceEntityToVO(entity, deviceMap.get(entity.getDeviceId()), null))
                .toList();
    }

    private DeviceChannelProcessorManager processorManager;
    @Autowired
    public void setProcessorManager(DeviceChannelProcessorManager deviceChannelProcessorManager) {
        this.processorManager = deviceChannelProcessorManager;
    }

    private ChannelService channelService;
    @Autowired
    public void setChannelService(ChannelService channelService) {
        this.channelService = channelService;
    }

    private ProtocolService protocolService;
    @Autowired
    public void setProtocolService(ProtocolService protocolService) {
        this.protocolService = protocolService;
    }

    private DeviceTypeService deviceTypeService;

    @Autowired
    public void setDeviceTypeService(DeviceTypeService deviceTypeService) {
        this.deviceTypeService = deviceTypeService;
    }

    private DeviceService deviceService;

    @Autowired
    public void setDeviceService(DeviceService deviceService) {
        this.deviceService = deviceService;
    }
}
